package com.example.webdownloadserver.core;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

import org.springframework.aop.framework.AdvisedSupport;
import org.springframework.aop.framework.AopProxy;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Service;

/**
 * 
 * @author lisy
 * @Describe This util can receive the ApplicationContext when it is loaded to
 *           get all the beans
 * @since
 */
@Service
public class TaskHandlerUtil implements ApplicationContextAware {

	private static ApplicationContext applicationContext;
	
	/**代理商下载 */
	public static Map<String, Object> downloadHandlerBeanMap = new HashMap<String, Object>();

	public static Map<String, Object> uploadHandlerBeanMap = new HashMap<String, Object>();

	// Get Application of Spring to this class
	@Override
	public void setApplicationContext(ApplicationContext arg0) throws BeansException {
		TaskHandlerUtil.applicationContext = arg0;
	}

	public static ApplicationContext getApplicationContext() {
		return applicationContext;
	}

	@SuppressWarnings("unchecked")
	public static <T> T getBean(String beanName) {
		cheakApplicationContext();
		return (T) applicationContext.getBean(beanName);
	}

	public static <T> T getBean(Class<T> clazz) {
		cheakApplicationContext();
		return (T) applicationContext.getBean(clazz);
	}

	// Get all classes with this annotation from the Application, based on the class
	// of the custom annotation passed in
	public static Map<String, Object> getMapbeanwithAnnotion(Class<? extends Annotation> cls) {
		Map<String, Object> map = new HashMap<String, Object>();
		map = applicationContext.getBeansWithAnnotation(cls);
		return map;
	}
	
	public static String getProfileActive() {
		 String[] activeProfiles = applicationContext.getEnvironment().getActiveProfiles();
		 return activeProfiles[0];
	}

	// Null checking
	private static void cheakApplicationContext() {
		if (applicationContext == null) {
			throw new IllegalStateException("ApplicaitonContext is not injected...");
		}
	}

	// Get the corresponding class by reflection operation
	public static Object getTarget(Object proxy) throws Exception {
		if (!AopUtils.isAopProxy(proxy)) {
			return proxy;// It's not a proxy object
		}
		// Reflect according to the JDK
		if (AopUtils.isJdkDynamicProxy(proxy)) {
			return getJdkDynamicProxyTargetObject(proxy);
		} else { // Reflect according to cglib
			return getCglibProxyTargetObject(proxy);
		}
	}

	private static Object getCglibProxyTargetObject(Object proxy) throws Exception {
		Field h = proxy.getClass().getDeclaredField("CGLIB$CALLBACK_0");
		h.setAccessible(true);
		Object dynamicAdvisedInterceptor = h.get(proxy);
		Field advised = dynamicAdvisedInterceptor.getClass().getDeclaredField("advised");
		advised.setAccessible(true);
		Object target = ((AdvisedSupport) advised.get(dynamicAdvisedInterceptor)).getTargetSource().getTarget();
		return target;
	}

	private static Object getJdkDynamicProxyTargetObject(Object proxy) throws Exception {
		Field h = proxy.getClass().getSuperclass().getDeclaredField("h");
		h.setAccessible(true);
		AopProxy aopProxy = (AopProxy) h.get(proxy);
		Field advised = aopProxy.getClass().getDeclaredField("advised");
		advised.setAccessible(true);
		Object target = ((AdvisedSupport) advised.get(aopProxy)).getTargetSource().getTarget();
		return target;
	}

}
